package fr.xebia.monitoring.appender;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.DisposableBean;

import fr.xebia.monitoring.MeasureHandler;
import fr.xebia.monitoring.MonitoringException;
import fr.xebia.monitoring.config.AppenderConfig;
import fr.xebia.monitoring.config.Property;

public class MeasureAppenderManager implements DisposableBean {

	private static final Logger logger = Logger.getLogger(MeasureAppenderManager.class);

	private List<MeasureAppender> appenders;
	private ScheduledExecutorService executorService;
	private MeasureHandler measureHandler;

	public void setMeasureHandler(MeasureHandler measureHandler) {
		this.measureHandler = measureHandler;
	}

	public void configureAppenders(List<AppenderConfig> appenderConfigList) {
		for (AppenderConfig appenderConfig : appenderConfigList) {
			addAppender(appenderConfig);
		}
	}

	public void addAppender(AppenderConfig appenderConfig) {
		MeasureAppender measureAppender = createAppender(appenderConfig);
		if (appenders == null) {
			appenders = new ArrayList<MeasureAppender>();
		}
		appenders.add(measureAppender);
	}

	@SuppressWarnings("unchecked")
	private MeasureAppender createAppender(AppenderConfig appenderConfig) {
		if (logger.isDebugEnabled()) {
			logger.debug("Adding new appender: " + appenderConfig.getClazz());
		}
		MeasureAppender measureAppender;
		try {
			Class<MeasureAppender> appenderClass = (Class<MeasureAppender>) Class.forName(appenderConfig.getClazz());
			measureAppender = appenderClass.newInstance();
		} catch (Exception e) {
			throw new MonitoringException("Can't initialize appender", e);
		}
		measureAppender.setMeasureHandler(measureHandler);
		try {
			for (Property property : appenderConfig.getProperty()) {
				BeanUtils.setProperty(measureAppender, property.getName(), property.getValue());
			}
		} catch (Exception e) {
			throw new MonitoringException("Can't configure appender properties", e);
		}
		return measureAppender;
	}

	public void startAppenders() {
		logger.debug("Starting Appenders");
		if (executorService == null) {
			executorService = Executors.newScheduledThreadPool(appenders.size());
		}
		for (MeasureAppender measureAppender : appenders) {
			ScheduledFuture<?> scheduledFuture = 
			executorService.scheduleAtFixedRate(measureAppender, measureAppender
					.getRefreshInterval(), measureAppender.getRefreshInterval(), TimeUnit.MILLISECONDS);
			if (logger.isDebugEnabled()) {
				logger.debug("Created schedule task: "+scheduledFuture);
			}
		}
	}

	public void stopAppenders() {
		if (executorService != null) {
			executorService.shutdown();
		}
	}

	/**
	 * Called by Spring on dispose
	 * @see org.springframework.beans.factory.DisposableBean#destroy()
	 */
	public void destroy() {
		stopAppenders();
	}
}
